package com.lft13.producterconsumer;

/**
 * Function: 		A {@code TestProducterConsumer} 测试：生产者消费者模型 ——> 利用缓冲区解决：管程法<br/>
 * Reason:   		ADD REASON.<br/>
 * <p>
 * 生产者，消费者，产品，缓冲区
 * <p>
 * Date:            2021-01-28 14:20<br/>
 * <p>
 * Class Name:      TestProducterConsumer<br/>
 * Package Name:    com.lft13.producterconsumer<br/>
 * @author Laifengting / E-mail:laifengting@foxmail.com
 * @version 1.0.0
 * @since JDK 8
 */
public class TestProducterConsumer {
	public static void main(String[] args) {
		SynContainer container = new SynContainer();
		new Producter(container).start();
		new Consumer(container).start();
	}
}

/**
 * 生产者
 */
class Producter extends Thread {
	SynContainer synContainer;
	
	public Producter(SynContainer synContainer) {
		this.synContainer = synContainer;
	}
	
	@Override
	public void run() {
		for (int i = 1; i <= 100; i++) {
			System.out.println("生产了 " + i + " 只鸡！");
			synContainer.push(new Product(i, "小鸡" + i));
		}
	}
}

/**
 * 消费者
 */
class Consumer extends Thread {
	SynContainer synContainer;
	
	public Consumer(SynContainer synContainer) {
		this.synContainer = synContainer;
	}
	
	@Override
	public void run() {
		for (int i = 1; i <= 100; i++) {
			System.out.println("消费了 " + i + " 只鸡！");
			Product product = synContainer.pop();
			System.out.println("我吃了一只id：" + product.id + ", 名叫：" + product.name + " 的鸡！");
		}
	}
}

/**
 * 产品
 */
class Product {
	/**
	 * 产品编号
	 */
	int id;
	
	/**
	 * 产品名称
	 */
	String name;
	
	public Product(int id, String name) {
		this.id = id;
		this.name = name;
	}
}

/**
 * 缓冲区（仓库）
 */
class SynContainer {
	/**
	 * 需要一个容器大小
	 */
	Product[] products = new Product[10];
	/**
	 * 容器计数器
	 */
	int count = 0;
	
	/**
	 * 生产者放入产品
	 */
	public synchronized void push(Product product) {
		// 如果容器满了。就需要等待消费者消费。
		if (count == products.length) {
			// 通知消费者消费。生产者等待。
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		// 如果没有满，我们就需要放入产品
		products[count] = product;
		count++;
		
		// 可以通知消费者消费。
		this.notifyAll();
	}
	
	// 消费者消费产品
	public synchronized Product pop() {
		// 判断是否有产品
		if (count == 0) {
			// 等待生产者生产，消费者等待。
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// 如果有库存，我们就消费库存。
		count--;
		Product product = products[count];
		
		// 吃完了通知生产者生产。
		this.notifyAll();
		
		return product;
	}
}
